/* liquidity.ado (STATA)
	Estimate price impact */

clear all

******************************************************************************
* Specify working directory
******************************************************************************

* For example
* cd "/Users/.../XYZ/"

global rawdata "Data/Raw_Data"
global tempdata "Data/RevisionRFS/temp_data"
global masterdata "Data/Master_Data"
global revisiondata "Data/RevisionRFS"
global revisionfigures = "Results/RevisionRFS/Figures"
global revisionoutput = "Results/RevisionRFS/Output"


#delimit ;
forval q = `=tq(2006q1)'(1)`=tq(2020q3)' {;

di %tq `q';
#delimit ;
/* Load data */
u date fundid bondid assetclass type_new2 
	holding aum_assetclass aum_tot
	_b_ss_price_iv lambda
	if date==`q' & holding>0
	using "${revisiondata}/counterfactuals/counterfactuals_data.dta", clear;

/* Construct variables */

gegen int row = group(bondid);

gegen int Nfundid3 = sum(type_new2==3), by(date bondid);
gegen int Nfundid5 = sum(type_new2==5), by(date bondid);

gegen Sholding = sum(holding), by(date bondid);
qui replace Sholding = holding/Sholding;

sort date bondid fundid;
by date bondid: gen byte first = _n==1;

gen weight_assetclass = aum_assetclass/aum_tot;
gen weight_conditional = holding/aum_assetclass;
gen weight = holding/aum_tot;

/* Impose downward sloping demand as in KY (2019) */
replace _b_ss_price_iv = 0.99 if _b_ss_price_iv >= 1; 

/* _b_ss_price_iv_type_ac_agg*/
bysort date fundid type_new2 assetclass: gen aum_type_assetclass_sum = aum_assetclass if _n == 1;
replace aum_type_assetclass_sum = 0 if aum_type_assetclass_sum ==.;
bysort date fundid type_new2 assetclass: gen _b_ss_price_iv_sum = _b_ss_price_iv if _n == 1;
replace _b_ss_price_iv_sum = 0 if _b_ss_price_iv_sum ==.;
gegen aum_assetclass_type_ac_agg=sum(aum_type_assetclass_sum), by(assetclass type_new2 date);
gegen _b_ss_price_iv_type_ac_agg = sum(_b_ss_price_iv_sum*aum_type_assetclass_sum/aum_assetclass_type_ac_agg), by(assetclass type_new2 date);

drop _b_ss_price_iv_sum;

/* _b_ss_price_iv_ac_agg*/
bysort date fundid assetclass: gen aum_assetclass_sum = aum_assetclass if _n == 1;
replace aum_assetclass_sum = 0 if aum_assetclass_sum ==.;
bysort date fundid assetclass: gen _b_ss_price_iv_sum = _b_ss_price_iv if _n == 1;
replace _b_ss_price_iv_sum = 0 if _b_ss_price_iv_sum ==.;
gegen aum_assetclass_ac_agg=sum(aum_assetclass_sum), by(assetclass date);
gegen _b_ss_price_iv_ac_agg = sum(_b_ss_price_iv_sum*aum_assetclass_sum/aum_assetclass_ac_agg), by(assetclass date);

/* _b_ss_price_iv_agg*/
gegen aum_assetclass_agg=sum(aum_assetclass_sum), by(date);
gegen _b_ss_price_iv_agg = sum(_b_ss_price_iv_sum*aum_assetclass_sum/aum_assetclass_agg), by(date);

/* lambda_agg */
bysort date fundid assetclass: gen lambda_sum = lambda if _n == 1;
replace lambda_sum = 0 if lambda_sum ==.;
gegen lambda_agg = sum(lambda_sum*aum_assetclass_sum/aum_assetclass_agg), by(date);

/* LOOP through columns */

qui sum row;
local Ncol = r(max);
display `Ncol';

qui forval col = 1/`Ncol' {;
	/* display `col'; */

	gegen rcassetclass = max((row==`col')*assetclass), by(date fundid);
	
	/* Full aggregate demand elasticity */
	gen z = weight*lambda*_b_ss_price_iv;
	replace z = - weight_conditional*lambda*_b_ss_price_iv + z + weight_conditional*_b_ss_price_iv if row!=`col' & assetclass==rcassetclass;
	replace z = 1 - _b_ss_price_iv + z if row==`col' & assetclass==rcassetclass;

	gegen Zcol = sum(z*Sholding), by(date bondid);
	
	/* Aggregate demand elasticity - allowing for within assetclass elasticity variation (no withing type variation) */
	gen z1 = weight*lambda*_b_ss_price_iv_type_ac_agg;
	replace z1 = - weight_conditional*lambda*_b_ss_price_iv_type_ac_agg + z1 + weight_conditional*_b_ss_price_iv_type_ac_agg if row!=`col' & assetclass==rcassetclass;
	replace z1 = 1 - _b_ss_price_iv_type_ac_agg + z1 if row==`col' & assetclass==rcassetclass;

	gegen Z1col = sum(z1*Sholding), by(date bondid);
	
	/* Aggregate demand elasticity - no within elasticity variation */
	gen z2 = weight*lambda*_b_ss_price_iv_ac_agg;
	replace z2 = - weight_conditional*lambda*_b_ss_price_iv_ac_agg + z2 + weight_conditional*_b_ss_price_iv_ac_agg if row!=`col' & assetclass==rcassetclass;
	replace z2 = 1 - _b_ss_price_iv_ac_agg + z2 if row==`col' & assetclass==rcassetclass;

	gegen Z2col = sum(z2*Sholding), by(date bondid);
	
	/* Aggregate demand elasticity - no within elasticity & no across elasticity variation */
	gen z3 = weight*lambda_agg*_b_ss_price_iv_agg;
	replace z3 = - weight_conditional*lambda_agg*_b_ss_price_iv_agg + z3 + weight_conditional*_b_ss_price_iv_agg if row!=`col' & assetclass==rcassetclass;
	replace z3 = 1 - _b_ss_price_iv_agg + z3 if row==`col' & assetclass==rcassetclass;

	gegen Z3col = sum(z3*Sholding), by(date bondid);

	/* Aggregate across investors */
	gen a = -lambda*weight;
	replace a = weight_conditional*lambda + a - weight_conditional if row!=`col' & assetclass==rcassetclass;
	replace a = 1 + a if row==`col' & assetclass==rcassetclass;
	
	gegen Acol = sum(a*Sholding), by(date bondid);

	/* Aggregate by mutual funds/etfs */
	gegen Bcol3 = sum((type_new2==3)*a*Sholding), by(date bondid);
	gegen Bcol5 = sum((type_new2==5)*a*Sholding), by(date bondid);

	/* Accumulate matrices by column */

	sort date row;
	putmata Zcol Z1col Z2col Z3col Acol Bcol* if first, replace;

	if `col'==1 {;
		mata: Zmat = Zcol;
		mata: Z1mat = Z1col;
		mata: Z2mat = Z2col;
		mata: Z3mat = Z3col;
		mata: Amat = Acol;
		mata: Bmat3 = Bcol3;
		mata: Bmat5 = Bcol5;
	};
	else {;
		mata: Zmat = (Zmat,Zcol);
		mata: Z1mat = (Z1mat,Z1col);
		mata: Z2mat = (Z2mat,Z2col);
		mata: Z3mat = (Z3mat,Z3col);
		mata: Amat = (Amat,Acol);
		mata: Bmat3 = (Bmat3,Bcol3);
		mata: Bmat5 = (Bmat5,Bcol5);
	};


	drop z z1 z2 z3 a Zcol Z1col Z2col Z3col Acol Bcol3 Bcol5 rcassetclass;
};


qui keep if first;

keep date bondid row Nfundid*;

sort date row;
qui putmata row, replace;

/* Estimate aggregate price impact */
mata: liquidA = diagonal(lusolve(Zmat,Amat));

getmata liquidA, id(row);

/* Estimate aggregate price impact -  within elasticity variation */
mata: liquidA1 = diagonal(lusolve(Z1mat,Amat));

getmata liquidA1, id(row);

/* Estimate aggregate price impact - no within elasticity variation */
mata: liquidA2 = diagonal(lusolve(Z2mat,Amat));

getmata liquidA2, id(row);

/* Estimate aggregate price impact - no within elasticity & no across elasticity variation */
mata: liquidA3 = diagonal(lusolve(Z3mat,Amat));

getmata liquidA3, id(row);

/* Estimate aggregate price impact by mutual funds */
mata: liquidmf = diagonal(lusolve(Zmat,Bmat3));

getmata liquidmf, id(row);

/* Estimate aggregate price impact by mutual funds - within elasticity variation */
mata: liquidmf1 = diagonal(lusolve(Z1mat,Bmat3));

getmata liquidmf1, id(row);

/* Estimate aggregate price impact by mutual funds - no within elasticity variation */
mata: liquidmf2 = diagonal(lusolve(Z2mat,Bmat3));

getmata liquidmf2, id(row);

/* Estimate aggregate price impact by mutual funds - no within elasticity & no across elasticity variation */
mata: liquidmf3 = diagonal(lusolve(Z3mat,Bmat3));

getmata liquidmf3, id(row);

/* Estimate aggregate price impact by etfs */
mata: liquidetf = diagonal(lusolve(Zmat,Bmat5));

getmata liquidetf, id(row);

/* Estimate aggregate price impact by mutual funds - within elasticity variation */
mata: liquidetf1 = diagonal(lusolve(Z1mat,Bmat5));

getmata liquidetf1, id(row);

/* Estimate aggregate price impact by mutual funds - no within elasticity variation */
mata: liquidetf2 = diagonal(lusolve(Z2mat,Bmat5));

getmata liquidetf2, id(row);

/* Estimate aggregate price impact by mutual funds - no within elasticity & no across elasticity variation */
mata: liquidetf3 = diagonal(lusolve(Z3mat,Bmat5));

getmata liquidetf3, id(row);

/* Label variables */

label var Nfundid3	"Number of observations: Mutual Funds";
label var Nfundid5	"Number of observations: ETFs";

label var liquidA	"Aggregate price impact";
label var liquidA1	"Aggregate price impact: within elasticity variation";
label var liquidA2	"Aggregate price impact: no within elasticity variation";
label var liquidA2	"Aggregate price impact: no within elasticity & no across elasticity variation";
label var liquidmf	"Aggregate price impact: Mutual Funds";
label var liquidmf1	"Aggregate price impact: MFs within elasticity variation";
label var liquidmf2	"Aggregate price impact: MFs no within elasticity variation";
label var liquidmf2	"Aggregate price impact: MFs no within elasticity & no across elasticity variation";
label var liquidetf	"Aggregate price impact: ETFs";
label var liquidetf1"Aggregate price impact: ETFs within elasticity variation";
label var liquidetf2"Aggregate price impact: ETFs no within elasticity variation";
label var liquidetf2"Aggregate price impact: ETFs no within elasticity & no across elasticity variation";

/* Save estimates */
sort date bondid;

qui save "${revisiondata}/liquidity/liquidity_`q'", replace;

};
